/*
 * Copyright 2024-2024 the original author or authors.
 */

package io.modelcontextprotocol.spec;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.modelcontextprotocol.util.Assert;
import io.modelcontextprotocol.util.ListUtils;
import lombok.ToString;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Based on the <a href="http://www.jsonrpc.org/specification">JSON-RPC 2.0
 * specification</a> and the <a href=
 * "https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.ts">Model
 * Context Protocol Schema</a>.
 *
 * @author Christian Tzolov
 */
public final class McpSchema {

    private static final Logger logger = LoggerFactory.getLogger(McpSchema.class);

    private McpSchema() {
    }

    public static final String LATEST_PROTOCOL_VERSION = "2024-11-05";

    public static final String JSONRPC_VERSION = "2.0";

    // ---------------------------
    // Method Names
    // ---------------------------

    // Lifecycle Methods
    public static final String METHOD_INITIALIZE = "initialize";

    public static final String METHOD_NOTIFICATION_INITIALIZED = "notifications/initialized";

    public static final String METHOD_PING = "ping";

    // Tool Methods
    public static final String METHOD_TOOLS_LIST = "tools/list";

    public static final String METHOD_TOOLS_CALL = "tools/call";

    public static final String METHOD_NOTIFICATION_TOOLS_LIST_CHANGED = "notifications/tools/list_changed";

    // Resources Methods
    public static final String METHOD_RESOURCES_LIST = "resources/list";

    public static final String METHOD_RESOURCES_READ = "resources/read";

    public static final String METHOD_NOTIFICATION_RESOURCES_LIST_CHANGED = "notifications/resources/list_changed";

    public static final String METHOD_RESOURCES_TEMPLATES_LIST = "resources/templates/list";

    public static final String METHOD_RESOURCES_SUBSCRIBE = "resources/subscribe";

    public static final String METHOD_RESOURCES_UNSUBSCRIBE = "resources/unsubscribe";

    // Prompt Methods
    public static final String METHOD_PROMPT_LIST = "prompts/list";

    public static final String METHOD_PROMPT_GET = "prompts/get";

    public static final String METHOD_NOTIFICATION_PROMPTS_LIST_CHANGED = "notifications/prompts/list_changed";

    public static final String METHOD_COMPLETION_COMPLETE = "completion/complete";

    // Logging Methods
    public static final String METHOD_LOGGING_SET_LEVEL = "logging/setLevel";

    public static final String METHOD_NOTIFICATION_MESSAGE = "notifications/message";

    // Roots Methods
    public static final String METHOD_ROOTS_LIST = "roots/list";

    public static final String METHOD_NOTIFICATION_ROOTS_LIST_CHANGED = "notifications/roots/list_changed";

    // Sampling Methods
    public static final String METHOD_SAMPLING_CREATE_MESSAGE = "sampling/createMessage";

    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    // ---------------------------
    // JSON-RPC Error Codes
    // ---------------------------

    /**
     * Standard error codes used in MCP JSON-RPC responses.
     */
    public static final class ErrorCodes {

        /**
         * Invalid JSON was received by the server.
         */
        public static final int PARSE_ERROR = -32700;

        /**
         * The JSON sent is not a valid Request object.
         */
        public static final int INVALID_REQUEST = -32600;

        /**
         * The method does not exist / is not available.
         */
        public static final int METHOD_NOT_FOUND = -32601;

        /**
         * Invalid method parameter(s).
         */
        public static final int INVALID_PARAMS = -32602;

        /**
         * Internal JSON-RPC error.
         */
        public static final int INTERNAL_ERROR = -32603;

    }

    public interface Request {
    }

    private static final TypeReference<HashMap<String, Object>> MAP_TYPE_REF = new TypeReference<HashMap<String, Object>>() {
    };

    /**
     * Deserializes a JSON string into a JSONRPCMessage object.
     *
     * @param objectMapper The ObjectMapper instance to use for deserialization
     * @param jsonText     The JSON string to deserialize
     * @return A JSONRPCMessage instance using either the {@link JSONRPCRequest},
     * {@link JSONRPCNotification}, or {@link JSONRPCResponse} classes.
     * @throws IOException              If there's an error during deserialization
     * @throws IllegalArgumentException If the JSON structure doesn't match any known
     *                                  message type
     */
    public static JSONRPCMessage deserializeJsonRpcMessage(ObjectMapper objectMapper, String jsonText)
            throws IOException {

        logger.debug("Received JSON message: {}", jsonText);

        Map<String, Object> map = objectMapper.readValue(jsonText, MAP_TYPE_REF);

        // Determine message type based on specific JSON structure
        if (map.containsKey("method") && map.containsKey("id")) {
            return objectMapper.convertValue(map, JSONRPCRequest.class);
        } else if (map.containsKey("method") && !map.containsKey("id")) {
            return objectMapper.convertValue(map, JSONRPCNotification.class);
        } else if (map.containsKey("result") || map.containsKey("error")) {
            return objectMapper.convertValue(map, JSONRPCResponse.class);
        }

        throw new IllegalArgumentException("Cannot deserialize JSONRPCMessage: " + jsonText);
    }

    // ---------------------------
    // JSON-RPC Message Types
    // ---------------------------
    public interface JSONRPCMessage {
        String jsonrpc();
    }

    @ToString
    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class JSONRPCRequest implements JSONRPCMessage {
        private final String jsonrpc;
        private final String method;
        private final Object id;
        private final Object params;

        public JSONRPCRequest(@JsonProperty("jsonrpc") String jsonrpc,
                              @JsonProperty("method") String method,
                              @JsonProperty("id") Object id,
                              @JsonProperty("params") Object params) {
            this.jsonrpc = jsonrpc;
            this.method = method;
            this.id = id;
            this.params = params;
        }

        @Override
        public String jsonrpc() {
            return jsonrpc;
        }

        public String method() {
            return method;
        }

        public Object id() {
            return id;
        }

        public Object params() {
            return params;
        }

        public Object getParams() {
            return params;
        }

        public String getMethod() {
            return method;
        }

        public String getJsonrpc() {
            return jsonrpc;
        }

        public Object getId() {
            return id;
        }
    }

    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class JSONRPCNotification implements JSONRPCMessage {
        private final String jsonrpc;
        private final String method;
        private final Object params;

        public JSONRPCNotification(@JsonProperty("jsonrpc") String jsonrpc,
                                   @JsonProperty("method") String method,
                                   @JsonProperty("params") Object params) {
            this.jsonrpc = jsonrpc;
            this.method = method;
            this.params = params;
        }

        @Override
        public String jsonrpc() {
            return jsonrpc;
        }

        public String getJsonrpc() {
            return jsonrpc;
        }

        public String getMethod() {
            return method;
        }

        public Object getParams() {
            return params;
        }

        public String method() {
            return method;
        }

        public Object params() {
            return params;
        }


    }

    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class JSONRPCResponse implements JSONRPCMessage {
        private final String jsonrpc;
        private final Object id;
        private final Object result;
        private final JSONRPCError error;

        public JSONRPCResponse(@JsonProperty("jsonrpc") String jsonrpc,
                               @JsonProperty("id") Object id,
                               @JsonProperty("result") Object result,
                               @JsonProperty("error") JSONRPCError error) {
            this.jsonrpc = jsonrpc;
            this.id = id;
            this.result = result;
            this.error = error;
        }

        @Override
        public String jsonrpc() {
            return jsonrpc;
        }

        public Object getId() {
            return id;
        }

        public String getJsonrpc() {
            return jsonrpc;
        }

        public JSONRPCError getError() {
            return error;
        }

        public Object getResult() {
            return result;
        }

        public Object id() {
            return id;
        }

        public Object result() {
            return result;
        }

        public JSONRPCError error() {
            return error;
        }

        @JsonInclude(JsonInclude.Include.NON_ABSENT)
        @JsonIgnoreProperties(ignoreUnknown = true)
        public static class JSONRPCError {
            private final int code;
            private final String message;
            private final Object data;

            public JSONRPCError(@JsonProperty("code") int code,
                                @JsonProperty("message") String message,
                                @JsonProperty("data") Object data) {
                this.code = code;
                this.message = message;
                this.data = data;
            }

            public int code() {
                return code;
            }

            public String message() {
                return message;
            }

            public Object data() {
                return data;
            }

            public Object getData() {
                return data;
            }

            public int getCode() {
                return code;
            }

            public String getMessage() {
                return message;
            }
        }
    }

    // ---------------------------
    // Initialization
    // ---------------------------
    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class InitializeRequest implements Request {
        private final String protocolVersion;
        private final ClientCapabilities capabilities;
        private final Implementation clientInfo;

        public InitializeRequest(@JsonProperty("protocolVersion") String protocolVersion,
                                 @JsonProperty("capabilities") ClientCapabilities capabilities,
                                 @JsonProperty("clientInfo") Implementation clientInfo) {
            this.protocolVersion = protocolVersion;
            this.capabilities = capabilities;
            this.clientInfo = clientInfo;
        }

        public String protocolVersion() {
            return protocolVersion;
        }

        public ClientCapabilities capabilities() {
            return capabilities;
        }

        public Implementation clientInfo() {
            return clientInfo;
        }

        public ClientCapabilities getCapabilities() {
            return capabilities;
        }

        public Implementation getClientInfo() {
            return clientInfo;
        }

        public String getProtocolVersion() {
            return protocolVersion;
        }
    }

    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class InitializeResult {
        private final String protocolVersion;
        private final ServerCapabilities capabilities;
        private final Implementation serverInfo;
        private final String instructions;

        public InitializeResult(@JsonProperty("protocolVersion") String protocolVersion,
                                @JsonProperty("capabilities") ServerCapabilities capabilities,
                                @JsonProperty("serverInfo") Implementation serverInfo,
                                @JsonProperty("instructions") String instructions) {
            this.protocolVersion = protocolVersion;
            this.capabilities = capabilities;
            this.serverInfo = serverInfo;
            this.instructions = instructions;
        }

        public String protocolVersion() {
            return protocolVersion;
        }

        public ServerCapabilities capabilities() {
            return capabilities;
        }

        public Implementation serverInfo() {
            return serverInfo;
        }

        public String instructions() {
            return instructions;
        }

        public Implementation getServerInfo() {
            return serverInfo;
        }

        public String getProtocolVersion() {
            return protocolVersion;
        }

        public ServerCapabilities getCapabilities() {
            return capabilities;
        }

        public String getInstructions() {
            return instructions;
        }
    }

    /**
     * Clients can implement additional features to enrich connected MCP servers with
     * additional capabilities. These capabilities can be used to extend the functionality
     * of the server, or to provide additional information to the server about the
     * client's capabilities.
     */
    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class ClientCapabilities {
        private final Map<String, Object> experimental;
        private final RootCapabilities roots;
        private final Sampling sampling;

        public ClientCapabilities(Map<String, Object> experimental,
                                  RootCapabilities roots,
                                  Sampling sampling) {
            this.experimental = experimental;
            this.roots = roots;
            this.sampling = sampling;
        }

        public Map<String, Object> experimental() {
            return experimental;
        }

        public RootCapabilities roots() {
            return roots;
        }

        public Sampling sampling() {
            return sampling;
        }

        public Map<String, Object> getExperimental() {
            return experimental;
        }

        public RootCapabilities getRoots() {
            return roots;
        }

        public Sampling getSampling() {
            return sampling;
        }

        public static Builder builder() {
            return new Builder();
        }

        public static class Builder {
            private Map<String, Object> experimental;
            private RootCapabilities roots;
            private Sampling sampling;

            public Builder experimental(Map<String, Object> experimental) {
                this.experimental = experimental;
                return this;
            }

            public Builder roots(Boolean listChanged) {
                this.roots = new RootCapabilities(listChanged);
                return this;
            }

            public Builder sampling() {
                this.sampling = new Sampling();
                return this;
            }

            public ClientCapabilities build() {
                return new ClientCapabilities(experimental, roots, sampling);
            }
        }

        /**
         * Roots define the boundaries of where servers can operate within the filesystem,
         * allowing them to understand which directories and files they have access to.
         * Servers can request the list of roots from supporting clients and
         * receive notifications when that list changes.
         */
        @JsonInclude(JsonInclude.Include.NON_ABSENT)
        @JsonIgnoreProperties(ignoreUnknown = true)
        public static class RootCapabilities {
            private final Boolean listChanged;

            public RootCapabilities(@JsonProperty("listChanged") Boolean listChanged) {
                this.listChanged = listChanged;
            }

            public Boolean listChanged() {
                return listChanged;
            }

            public Boolean getListChanged() {
                return listChanged;
            }
        }

        /**
         * Provides a standardized way for servers to request LLM
         * sampling ("completions" or "generations") from language
         * models via clients. This flow allows clients to maintain
         * control over model access, selection, and permissions
         * while enabling servers to leverage AI capabilities—with
         * no server API keys necessary. Servers can request text or
         * image-based interactions and optionally include context
         * from MCP servers in their prompts.
         */
        @JsonInclude(JsonInclude.Include.NON_ABSENT)
        public static class Sampling {
        }
    }

    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class ServerCapabilities {
        private final CompletionCapabilities completions;
        private final Map<String, Object> experimental;
        private final LoggingCapabilities logging;
        private final PromptCapabilities prompts;
        private final ResourceCapabilities resources;
        private final ToolCapabilities tools;

        public ServerCapabilities(CompletionCapabilities completions,
                                  Map<String, Object> experimental,
                                  LoggingCapabilities logging,
                                  PromptCapabilities prompts,
                                  ResourceCapabilities resources,
                                  ToolCapabilities tools) {
            this.completions = completions;
            this.experimental = experimental;
            this.logging = logging;
            this.prompts = prompts;
            this.resources = resources;
            this.tools = tools;
        }

        public CompletionCapabilities completions() {
            return completions;
        }

        public Map<String, Object> experimental() {
            return experimental;
        }

        public LoggingCapabilities logging() {
            return logging;
        }

        public PromptCapabilities prompts() {
            return prompts;
        }

        public ResourceCapabilities resources() {
            return resources;
        }

        public ToolCapabilities tools() {
            return tools;
        }

        public Map<String, Object> getExperimental() {
            return experimental;
        }

        public CompletionCapabilities getCompletions() {
            return completions;
        }

        public LoggingCapabilities getLogging() {
            return logging;
        }

        public PromptCapabilities getPrompts() {
            return prompts;
        }

        public ResourceCapabilities getResources() {
            return resources;
        }

        public ToolCapabilities getTools() {
            return tools;
        }

        public static Builder builder() {
            return new Builder();
        }

        public static class Builder {
            private CompletionCapabilities completions;
            private Map<String, Object> experimental;
            private LoggingCapabilities logging = new LoggingCapabilities();
            private PromptCapabilities prompts;
            private ResourceCapabilities resources;
            private ToolCapabilities tools;

            public Builder completions() {
                this.completions = new CompletionCapabilities();
                return this;
            }

            public Builder experimental(Map<String, Object> experimental) {
                this.experimental = experimental;
                return this;
            }

            public Builder logging() {
                this.logging = new LoggingCapabilities();
                return this;
            }

            public Builder prompts(Boolean listChanged) {
                this.prompts = new PromptCapabilities(listChanged);
                return this;
            }

            public Builder resources(Boolean subscribe, Boolean listChanged) {
                this.resources = new ResourceCapabilities(subscribe, listChanged);
                return this;
            }

            public Builder tools(Boolean listChanged) {
                this.tools = new ToolCapabilities(listChanged);
                return this;
            }

            public ServerCapabilities build() {
                return new ServerCapabilities(completions, experimental, logging, prompts, resources, tools);
            }
        }

        @JsonInclude(JsonInclude.Include.NON_ABSENT)
        public static class CompletionCapabilities {
        }

        @JsonInclude(JsonInclude.Include.NON_ABSENT)
        public static class LoggingCapabilities {
        }

        @JsonInclude(JsonInclude.Include.NON_ABSENT)
        public static class PromptCapabilities {
            private final Boolean listChanged;

            public PromptCapabilities(@JsonProperty("listChanged") Boolean listChanged) {
                this.listChanged = listChanged;
            }

            public Boolean listChanged() {
                return listChanged;
            }

            public Boolean getListChanged() {
                return listChanged;
            }
        }

        @JsonInclude(JsonInclude.Include.NON_ABSENT)
        public static class ResourceCapabilities {
            private final Boolean subscribe;
            private final Boolean listChanged;

            public ResourceCapabilities(@JsonProperty("subscribe") Boolean subscribe,
                                        @JsonProperty("listChanged") Boolean listChanged) {
                this.subscribe = subscribe;
                this.listChanged = listChanged;
            }

            public Boolean subscribe() {
                return subscribe;
            }

            public Boolean listChanged() {
                return listChanged;
            }

            public Boolean getListChanged() {
                return listChanged;
            }

            public Boolean getSubscribe() {
                return subscribe;
            }
        }

        @JsonInclude(JsonInclude.Include.NON_ABSENT)
        public static class ToolCapabilities {
            private final Boolean listChanged;

            public ToolCapabilities(@JsonProperty("listChanged") Boolean listChanged) {
                this.listChanged = listChanged;
            }

            public Boolean listChanged() {
                return listChanged;
            }
        }
    }

    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class Implementation {
        private final String name;
        private final String version;

        public Implementation(@JsonProperty("name") String name,
                              @JsonProperty("version") String version) {
            this.name = name;
            this.version = version;
        }

        public String name() {
            return name;
        }

        public String version() {
            return version;
        }

        public String getName() {
            return name;
        }

        public String getVersion() {
            return version;
        }
    }

    // Existing Enums and Base Types (from previous implementation)
    public enum Role {
        @JsonProperty("user") USER,
        @JsonProperty("assistant") ASSISTANT
    }

    // ---------------------------
    // Resource Interfaces
    // ---------------------------

    /**
     * Base for objects that include optional annotations for the client. The client can
     * use annotations to inform how objects are used or displayed
     */
    public interface Annotated {
        Annotations annotations();
    }

    /**
     * Optional annotations for the client. The client can use annotations to inform how
     * objects are used or displayed.
     */
    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class Annotations {
        private final List<Role> audience;
        private final Double priority;

        public Annotations(@JsonProperty("audience") List<Role> audience,
                           @JsonProperty("priority") Double priority) {
            this.audience = audience;
            this.priority = priority;
        }

        public List<Role> audience() {
            return audience;
        }

        public Double priority() {
            return priority;
        }

        public Double getPriority() {
            return priority;
        }

        public List<Role> getAudience() {
            return audience;
        }
    }

    /**
     * A known resource that the server is capable of reading.
     */
    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class Resource implements Annotated {
        private final String uri;
        private final String name;
        private final String description;
        private final String mimeType;
        private final Annotations annotations;

        public Resource(@JsonProperty("uri") String uri,
                        @JsonProperty("name") String name,
                        @JsonProperty("description") String description,
                        @JsonProperty("mimeType") String mimeType,
                        @JsonProperty("annotations") Annotations annotations) {
            this.uri = uri;
            this.name = name;
            this.description = description;
            this.mimeType = mimeType;
            this.annotations = annotations;
        }

        public String uri() {
            return uri;
        }

        public String name() {
            return name;
        }

        public String description() {
            return description;
        }

        public String mimeType() {
            return mimeType;
        }

        @Override
        public Annotations annotations() {
            return annotations;
        }

        public String getName() {
            return name;
        }

        public Annotations getAnnotations() {
            return annotations;
        }

        public String getDescription() {
            return description;
        }

        public String getMimeType() {
            return mimeType;
        }

        public String getUri() {
            return uri;
        }
    }

    /**
     * Resource templates allow servers to expose parameterized resources using URI
     * templates.
     */
    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class ResourceTemplate implements Annotated {
        private final String uriTemplate;
        private final String name;
        private final String description;
        private final String mimeType;
        private final Annotations annotations;

        public ResourceTemplate(@JsonProperty("uriTemplate") String uriTemplate,
                                @JsonProperty("name") String name,
                                @JsonProperty("description") String description,
                                @JsonProperty("mimeType") String mimeType,
                                @JsonProperty("annotations") Annotations annotations) {
            this.uriTemplate = uriTemplate;
            this.name = name;
            this.description = description;
            this.mimeType = mimeType;
            this.annotations = annotations;
        }

        public String uriTemplate() {
            return uriTemplate;
        }

        public String name() {
            return name;
        }

        public String description() {
            return description;
        }

        public String mimeType() {
            return mimeType;
        }

        @Override
        public Annotations annotations() {
            return annotations;
        }

        public String getDescription() {
            return description;
        }

        public Annotations getAnnotations() {
            return annotations;
        }

        public String getMimeType() {
            return mimeType;
        }

        public String getName() {
            return name;
        }

        public String getUriTemplate() {
            return uriTemplate;
        }
    }

    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class ListResourcesResult {
        private final List<Resource> resources;
        private final String nextCursor;

        public ListResourcesResult(@JsonProperty("resources") List<Resource> resources,
                                   @JsonProperty("nextCursor") String nextCursor) {
            this.resources = resources;
            this.nextCursor = nextCursor;
        }

        public List<Resource> resources() {
            return resources;
        }

        public String nextCursor() {
            return nextCursor;
        }

        public List<Resource> getResources() {
            return resources;
        }

        public String getNextCursor() {
            return nextCursor;
        }
    }

    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class ListResourceTemplatesResult {
        private final List<ResourceTemplate> resourceTemplates;
        private final String nextCursor;

        public ListResourceTemplatesResult(@JsonProperty("resourceTemplates") List<ResourceTemplate> resourceTemplates,
                                           @JsonProperty("nextCursor") String nextCursor) {
            this.resourceTemplates = resourceTemplates;
            this.nextCursor = nextCursor;
        }

        public List<ResourceTemplate> resourceTemplates() {
            return resourceTemplates;
        }

        public String nextCursor() {
            return nextCursor;
        }

        public List<ResourceTemplate> getResourceTemplates() {
            return resourceTemplates;
        }

        public String getNextCursor() {
            return nextCursor;
        }
    }

    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class ReadResourceRequest {
        private final String uri;

        public ReadResourceRequest(@JsonProperty("uri") String uri) {
            this.uri = uri;
        }

        public String uri() {
            return uri;
        }

        public String getUri() {
            return uri;
        }

    }

    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class ReadResourceResult {
        private final List<ResourceContents> contents;

        public ReadResourceResult(@JsonProperty("contents") List<ResourceContents> contents) {
            this.contents = contents;
        }

        public List<ResourceContents> contents() {
            return contents;
        }

        public List<ResourceContents> getContents() {
            return contents;
        }
    }

    /**
     * Sent from the client to request resources/updated notifications from the server
     * whenever a particular resource changes.
     */
    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class SubscribeRequest {
        private final String uri;

        public SubscribeRequest(@JsonProperty("uri") String uri) {
            this.uri = uri;
        }

        public String uri() {
            return uri;
        }

        public String getUri() {
            return uri;
        }

    }

    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class UnsubscribeRequest {
        private final String uri;

        public UnsubscribeRequest(@JsonProperty("uri") String uri) {
            this.uri = uri;
        }

        public String uri() {
            return uri;
        }

        public String getUri() {
            return uri;
        }
    }

    /**
     * The contents of a specific resource or sub-resource.
     */
    @JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION, include = As.PROPERTY)
    @JsonSubTypes({@JsonSubTypes.Type(value = TextResourceContents.class, name = "text"),
            @JsonSubTypes.Type(value = BlobResourceContents.class, name = "blob")})
    public interface ResourceContents {
        /**
         * The URI of this resource.
         *
         * @return the URI of this resource.
         */
        String uri();

        /**
         * The MIME type of this resource.
         *
         * @return the MIME type of this resource.
         */
        String mimeType();
    }

    /**
     * Text contents of a resource.
     */
    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class TextResourceContents implements ResourceContents {
        private final String uri;
        private final String mimeType;
        private final String text;

        public TextResourceContents(@JsonProperty("uri") String uri,
                                    @JsonProperty("mimeType") String mimeType,
                                    @JsonProperty("text") String text) {
            this.uri = uri;
            this.mimeType = mimeType;
            this.text = text;
        }

        @Override
        public String uri() {
            return uri;
        }

        @Override
        public String mimeType() {
            return mimeType;
        }

        public String text() {
            return text;
        }

        public String getUri() {
            return uri;
        }

        public String getMimeType() {
            return mimeType;
        }

        public String getText() {
            return text;
        }
    }

    /**
     * Binary contents of a resource.
     */
    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class BlobResourceContents implements ResourceContents {
        private final String uri;
        private final String mimeType;
        private final String blob;

        public BlobResourceContents(@JsonProperty("uri") String uri,
                                    @JsonProperty("mimeType") String mimeType,
                                    @JsonProperty("blob") String blob) {
            this.uri = uri;
            this.mimeType = mimeType;
            this.blob = blob;
        }

        @Override
        public String uri() {
            return uri;
        }

        @Override
        public String mimeType() {
            return mimeType;
        }

        public String blob() {
            return blob;
        }

        public String getMimeType() {
            return mimeType;
        }

        public String getUri() {
            return uri;
        }

        public String getBlob() {
            return blob;
        }
    }

    // ---------------------------
    // Prompt Interfaces
    // ---------------------------

    /**
     * A prompt or prompt template that the server offers.
     */
    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class Prompt {
        private final String name;
        private final String description;
        private final List<PromptArgument> arguments;

        public Prompt(@JsonProperty("name") String name,
                      @JsonProperty("description") String description,
                      @JsonProperty("arguments") List<PromptArgument> arguments) {
            this.name = name;
            this.description = description;
            this.arguments = arguments;
        }

        public String name() {
            return name;
        }

        public String description() {
            return description;
        }

        public List<PromptArgument> arguments() {
            return arguments;
        }

        public String getDescription() {
            return description;
        }

        public String getName() {
            return name;
        }

        public List<PromptArgument> getArguments() {
            return arguments;
        }
    }

    /**
     * Describes an argument that a prompt can accept.
     */
    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class PromptArgument {
        private final String name;
        private final String description;
        private final Boolean required;

        public PromptArgument(@JsonProperty("name") String name,
                              @JsonProperty("description") String description,
                              @JsonProperty("required") Boolean required) {
            this.name = name;
            this.description = description;
            this.required = required;
        }

        public String name() {
            return name;
        }

        public String description() {
            return description;
        }

        public Boolean required() {
            return required;
        }

        public String getDescription() {
            return description;
        }

        public String getName() {
            return name;
        }

        public Boolean getRequired() {
            return required;
        }
    }

    /**
     * Describes a message returned as part of a prompt.
     * <p>
     * This is similar to `SamplingMessage`, but also supports the embedding of resources
     * from the MCP server.
     */
    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class PromptMessage {
        private final Role role;
        private final Content content;

        public PromptMessage(@JsonProperty("role") Role role,
                             @JsonProperty("content") Content content) {
            this.role = role;
            this.content = content;
        }

        public Role role() {
            return role;
        }

        public Content content() {
            return content;
        }

        public Content getContent() {
            return content;
        }

        public Role getRole() {
            return role;
        }
    }

    /**
     * The server's response to a prompts/list request from the client.
     */
    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class ListPromptsResult {
        private final List<Prompt> prompts;
        private final String nextCursor;

        public ListPromptsResult(@JsonProperty("prompts") List<Prompt> prompts,
                                 @JsonProperty("nextCursor") String nextCursor) {
            this.prompts = prompts;
            this.nextCursor = nextCursor;
        }

        public List<Prompt> prompts() {
            return prompts;
        }

        public String nextCursor() {
            return nextCursor;
        }

        public String getNextCursor() {
            return nextCursor;
        }

        public List<Prompt> getPrompts() {
            return prompts;
        }
    }

    /**
     * Used by the client to get a prompt provided by the server.
     */
    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class GetPromptRequest implements Request {
        private final String name;
        private final Map<String, Object> arguments;

        public GetPromptRequest(@JsonProperty("name") String name,
                                @JsonProperty("arguments") Map<String, Object> arguments) {
            this.name = name;
            this.arguments = arguments;
        }

        public String name() {
            return name;
        }

        public Map<String, Object> arguments() {
            return arguments;
        }

        public String getName() {
            return name;
        }

        public Map<String, Object> getArguments() {
            return arguments;
        }
    }

    /**
     * The server's response to a prompts/get request from the client.
     */
    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class GetPromptResult {
        private final String description;
        private final List<PromptMessage> messages;

        public GetPromptResult(@JsonProperty("description") String description,
                               @JsonProperty("messages") List<PromptMessage> messages) {
            this.description = description;
            this.messages = messages;
        }

        public String description() {
            return description;
        }

        public List<PromptMessage> messages() {
            return messages;
        }

        public String getDescription() {
            return description;
        }

        public List<PromptMessage> getMessages() {
            return messages;
        }
    }

    // ---------------------------
    // Tool Interfaces
    // ---------------------------

    /**
     * The server's response to a tools/list request from the client.
     */
    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class ListToolsResult {
        private final List<Tool> tools;
        private final String nextCursor;

        public ListToolsResult(@JsonProperty("tools") List<Tool> tools,
                               @JsonProperty("nextCursor") String nextCursor) {
            this.tools = tools;
            this.nextCursor = nextCursor;
        }

        public List<Tool> tools() {
            return tools;
        }

        public String nextCursor() {
            return nextCursor;
        }

        public String getNextCursor() {
            return nextCursor;
        }

        public List<Tool> getTools() {
            return tools;
        }
    }

    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class JsonSchema {
        private final String type;
        private final Map<String, Object> properties;
        private final List<String> required;
        private final Boolean additionalProperties;
        private final Map<String, Object> defs;
        private final Map<String, Object> definitions;

        public JsonSchema(@JsonProperty("type") String type,
                          @JsonProperty("properties") Map<String, Object> properties,
                          @JsonProperty("required") List<String> required,
                          @JsonProperty("additionalProperties") Boolean additionalProperties,
                          @JsonProperty("$defs") Map<String, Object> defs,
                          @JsonProperty("definitions") Map<String, Object> definitions) {
            this.type = type;
            this.properties = properties;
            this.required = required;
            this.additionalProperties = additionalProperties;
            this.defs = defs;
            this.definitions = definitions;
        }

        public String type() {
            return type;
        }

        public Map<String, Object> properties() {
            return properties;
        }

        public List<String> required() {
            return required;
        }

        public Boolean additionalProperties() {
            return additionalProperties;
        }

        public Map<String, Object> defs() {
            return defs;
        }

        public Map<String, Object> definitions() {
            return definitions;
        }

        public Boolean getAdditionalProperties() {
            return additionalProperties;
        }

        public List<String> getRequired() {
            return required;
        }

        public Map<String, Object> getDefinitions() {
            return definitions;
        }

        public Map<String, Object> getDefs() {
            return defs;
        }

        public Map<String, Object> getProperties() {
            return properties;
        }

        public String getType() {
            return type;
        }
    }

    /**
     * Represents a tool that the server provides. Tools enable servers to expose
     * executable functionality to the system. Through these tools, you can interact with
     * external systems, perform computations, and take actions in the real world.
     */
    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class Tool {
        private final String name;
        private final String description;
        private final JsonSchema inputSchema;

        public Tool(@JsonProperty("name") String name,
                    @JsonProperty("description") String description,
                    @JsonProperty("inputSchema") JsonSchema inputSchema) {
            this.name = name;
            this.description = description;
            this.inputSchema = inputSchema;
        }

        public Tool(String name, String description, String schema) {
            this(name, description, parseSchema(schema));
        }

        public String name() {
            return name;
        }

        public String description() {
            return description;
        }

        public JsonSchema inputSchema() {
            return inputSchema;
        }

        private static JsonSchema parseSchema(String schema) {
            try {
                return OBJECT_MAPPER.readValue(schema, JsonSchema.class);
            } catch (IOException e) {
                throw new IllegalArgumentException("Invalid schema: " + schema, e);
            }
        }

        public String getDescription() {
            return description;
        }

        public String getName() {
            return name;
        }

        public JsonSchema getInputSchema() {
            return inputSchema;
        }
    }

    /**
     * Used by the client to call a tool provided by the server.
     */
    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class CallToolRequest implements Request {
        private final String name;
        private final Map<String, Object> arguments;

        public CallToolRequest(@JsonProperty("name") String name,
                               @JsonProperty("arguments") Map<String, Object> arguments) {
            this.name = name;
            this.arguments = arguments;
        }

        public CallToolRequest(String name, String jsonArguments) {
            this(name, parseJsonArguments(jsonArguments));
        }

        public String name() {
            return name;
        }

        public Map<String, Object> arguments() {
            return arguments;
        }

        public String getName() {
            return name;
        }

        public Map<String, Object> getArguments() {
            return arguments;
        }

        private static Map<String, Object> parseJsonArguments(String jsonArguments) {
            try {
                return OBJECT_MAPPER.readValue(jsonArguments, MAP_TYPE_REF);
            } catch (IOException e) {
                throw new IllegalArgumentException("Invalid arguments: " + jsonArguments, e);
            }
        }
    }

    /**
     * The server's response to a tools/call request from the client.
     */
    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class CallToolResult {
        private final List<Content> content;
        private final Boolean isError;

        public CallToolResult(@JsonProperty("content") List<Content> content,
                              @JsonProperty("isError") Boolean isError) {
            this.content = content;
            this.isError = isError;
        }

        public CallToolResult(String content, Boolean isError) {
            this(ListUtils.of(new TextContent(content)), isError);
        }

        public List<Content> content() {
            return content;
        }

        public Boolean isError() {
            return isError;
        }

        public Boolean getError() {
            return isError;
        }

        public List<Content> getContent() {
            return content;
        }


        public static Builder builder() {
            return new Builder();
        }

        public static class Builder {
            private List<Content> content = new ArrayList<>();
            private Boolean isError;

            public Builder content(List<Content> content) {
                Assert.notNull(content, "content must not be null");
                this.content = content;
                return this;
            }

            public Builder textContent(List<String> textContent) {
                Assert.notNull(textContent, "textContent must not be null");
                for (String text : textContent) {
                    content.add(new TextContent(text));
                }
                return this;
            }

            public Builder addContent(Content contentItem) {
                Assert.notNull(contentItem, "contentItem must not be null");
                if (this.content == null) {
                    this.content = new ArrayList<>();
                }
                this.content.add(contentItem);
                return this;
            }

            public Builder addTextContent(String text) {
                Assert.notNull(text, "text must not be null");
                return addContent(new TextContent(text));
            }

            public Builder isError(Boolean isError) {
                Assert.notNull(isError, "isError must not be null");
                this.isError = isError;
                return this;
            }

            public CallToolResult build() {
                return new CallToolResult(content, isError);
            }
        }
    }

    // ---------------------------
    // Sampling Interfaces
    // ---------------------------
    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class ModelPreferences {
        private final List<ModelHint> hints;
        private final Double costPriority;
        private final Double speedPriority;
        private final Double intelligencePriority;

        public ModelPreferences(@JsonProperty("hints") List<ModelHint> hints,
                                @JsonProperty("costPriority") Double costPriority,
                                @JsonProperty("speedPriority") Double speedPriority,
                                @JsonProperty("intelligencePriority") Double intelligencePriority) {
            this.hints = hints;
            this.costPriority = costPriority;
            this.speedPriority = speedPriority;
            this.intelligencePriority = intelligencePriority;
        }

        public List<ModelHint> hints() {
            return hints;
        }

        public Double costPriority() {
            return costPriority;
        }

        public Double speedPriority() {
            return speedPriority;
        }

        public Double intelligencePriority() {
            return intelligencePriority;
        }

        public static Builder builder() {
            return new Builder();
        }

        public static class Builder {
            private List<ModelHint> hints;
            private Double costPriority;
            private Double speedPriority;
            private Double intelligencePriority;

            public Builder hints(List<ModelHint> hints) {
                this.hints = hints;
                return this;
            }

            public Builder addHint(String name) {
                if (this.hints == null) {
                    this.hints = new ArrayList<>();
                }
                this.hints.add(new ModelHint(name));
                return this;
            }

            public Builder costPriority(Double costPriority) {
                this.costPriority = costPriority;
                return this;
            }

            public Builder speedPriority(Double speedPriority) {
                this.speedPriority = speedPriority;
                return this;
            }

            public Builder intelligencePriority(Double intelligencePriority) {
                this.intelligencePriority = intelligencePriority;
                return this;
            }

            public ModelPreferences build() {
                return new ModelPreferences(hints, costPriority, speedPriority, intelligencePriority);
            }
        }
    }

    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class ModelHint {
        private final String name;

        public ModelHint(@JsonProperty("name") String name) {
            this.name = name;
        }

        public static ModelHint of(String name) {
            return new ModelHint(name);
        }

        public String name() {
            return name;
        }

        public String getName() {
            return name;
        }
    }

    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class SamplingMessage {
        private final Role role;
        private final Content content;

        public SamplingMessage(@JsonProperty("role") Role role,
                               @JsonProperty("content") Content content) {
            this.role = role;
            this.content = content;
        }

        public Role role() {
            return role;
        }

        public Content content() {
            return content;
        }

        public Content getContent() {
            return content;
        }

        public Role getRole() {
            return role;
        }
    }

    // Sampling and Message Creation
    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class CreateMessageRequest implements Request {
        private final List<SamplingMessage> messages;
        private final ModelPreferences modelPreferences;
        private final String systemPrompt;
        private final ContextInclusionStrategy includeContext;
        private final Double temperature;
        private final int maxTokens;
        private final List<String> stopSequences;
        private final Map<String, Object> metadata;

        public CreateMessageRequest(@JsonProperty("messages") List<SamplingMessage> messages,
                                    @JsonProperty("modelPreferences") ModelPreferences modelPreferences,
                                    @JsonProperty("systemPrompt") String systemPrompt,
                                    @JsonProperty("includeContext") ContextInclusionStrategy includeContext,
                                    @JsonProperty("temperature") Double temperature,
                                    @JsonProperty("maxTokens") int maxTokens,
                                    @JsonProperty("stopSequences") List<String> stopSequences,
                                    @JsonProperty("metadata") Map<String, Object> metadata) {
            this.messages = messages;
            this.modelPreferences = modelPreferences;
            this.systemPrompt = systemPrompt;
            this.includeContext = includeContext;
            this.temperature = temperature;
            this.maxTokens = maxTokens;
            this.stopSequences = stopSequences;
            this.metadata = metadata;
        }

        public enum ContextInclusionStrategy {
            @JsonProperty("none") NONE,
            @JsonProperty("thisServer") THIS_SERVER,
            @JsonProperty("allServers") ALL_SERVERS
        }

        public List<SamplingMessage> messages() {
            return messages;
        }

        public ModelPreferences modelPreferences() {
            return modelPreferences;
        }

        public String systemPrompt() {
            return systemPrompt;
        }

        public ContextInclusionStrategy includeContext() {
            return includeContext;
        }

        public Double temperature() {
            return temperature;
        }

        public int maxTokens() {
            return maxTokens;
        }

        public List<String> stopSequences() {
            return stopSequences;
        }

        public Map<String, Object> metadata() {
            return metadata;
        }

        public ContextInclusionStrategy getIncludeContext() {
            return includeContext;
        }

        public Double getTemperature() {
            return temperature;
        }

        public int getMaxTokens() {
            return maxTokens;
        }

        public List<SamplingMessage> getMessages() {
            return messages;
        }

        public List<String> getStopSequences() {
            return stopSequences;
        }

        public Map<String, Object> getMetadata() {
            return metadata;
        }

        public ModelPreferences getModelPreferences() {
            return modelPreferences;
        }

        public String getSystemPrompt() {
            return systemPrompt;
        }


        public static Builder builder() {
            return new Builder();
        }

        public static class Builder {
            private List<SamplingMessage> messages;
            private ModelPreferences modelPreferences;
            private String systemPrompt;
            private ContextInclusionStrategy includeContext;
            private Double temperature;
            private int maxTokens;
            private List<String> stopSequences;
            private Map<String, Object> metadata;

            public Builder messages(List<SamplingMessage> messages) {
                this.messages = messages;
                return this;
            }

            public Builder modelPreferences(ModelPreferences modelPreferences) {
                this.modelPreferences = modelPreferences;
                return this;
            }

            public Builder systemPrompt(String systemPrompt) {
                this.systemPrompt = systemPrompt;
                return this;
            }

            public Builder includeContext(ContextInclusionStrategy includeContext) {
                this.includeContext = includeContext;
                return this;
            }

            public Builder temperature(Double temperature) {
                this.temperature = temperature;
                return this;
            }

            public Builder maxTokens(int maxTokens) {
                this.maxTokens = maxTokens;
                return this;
            }

            public Builder stopSequences(List<String> stopSequences) {
                this.stopSequences = stopSequences;
                return this;
            }

            public Builder metadata(Map<String, Object> metadata) {
                this.metadata = metadata;
                return this;
            }

            public CreateMessageRequest build() {
                return new CreateMessageRequest(messages, modelPreferences, systemPrompt,
                        includeContext, temperature, maxTokens, stopSequences, metadata);
            }
        }
    }

    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class CreateMessageResult {
        private final Role role;
        private final Content content;
        private final String model;
        private final StopReason stopReason;

        public CreateMessageResult(@JsonProperty("role") Role role,
                                   @JsonProperty("content") Content content,
                                   @JsonProperty("model") String model,
                                   @JsonProperty("stopReason") StopReason stopReason) {
            this.role = role;
            this.content = content;
            this.model = model;
            this.stopReason = stopReason;
        }

        public enum StopReason {
            @JsonProperty("endTurn") END_TURN,
            @JsonProperty("stopSequence") STOP_SEQUENCE,
            @JsonProperty("maxTokens") MAX_TOKENS
        }

        public Role role() {
            return role;
        }

        public Content content() {
            return content;
        }

        public String model() {
            return model;
        }

        public StopReason stopReason() {
            return stopReason;
        }


        public Content getContent() {
            return content;
        }

        public Role getRole() {
            return role;
        }

        public StopReason getStopReason() {
            return stopReason;
        }

        public String getModel() {
            return model;
        }

        public static Builder builder() {
            return new Builder();
        }

        public static class Builder {
            private Role role = Role.ASSISTANT;
            private Content content;
            private String model;
            private StopReason stopReason = StopReason.END_TURN;

            public Builder role(Role role) {
                this.role = role;
                return this;
            }

            public Builder content(Content content) {
                this.content = content;
                return this;
            }

            public Builder model(String model) {
                this.model = model;
                return this;
            }

            public Builder stopReason(StopReason stopReason) {
                this.stopReason = stopReason;
                return this;
            }

            public Builder message(String message) {
                this.content = new TextContent(message);
                return this;
            }

            public CreateMessageResult build() {
                return new CreateMessageResult(role, content, model, stopReason);
            }
        }
    }

    // ---------------------------
    // Pagination Interfaces
    // ---------------------------
    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class PaginatedRequest {
        private final String cursor;

        public PaginatedRequest(@JsonProperty("cursor") String cursor) {
            this.cursor = cursor;
        }

        public String cursor() {
            return cursor;
        }

        public String getCursor() {
            return cursor;
        }
    }

    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class LoggingMessageNotification {

        private final LoggingLevel level;
        private final String logger;
        private final String data;

        public LoggingMessageNotification(
                @JsonProperty("level") LoggingLevel level,
                @JsonProperty("logger") String logger,
                @JsonProperty("data") String data) {

            this.level = level;
            this.logger = logger;
            this.data = data;
        }

        public LoggingLevel level() {
            return level;
        }

        public String logger() {
            return logger;
        }

        public String data() {
            return data;
        }

        public LoggingLevel getLevel() {
            return level;
        }

        public String getData() {
            return data;
        }

        public String getLogger() {
            return logger;
        }

        public static Builder builder() {
            return new Builder();
        }

        public static class Builder {
            private LoggingLevel level = LoggingLevel.INFO;
            private String logger = "server";
            private String data;

            public Builder level(LoggingLevel level) {
                this.level = level;
                return this;
            }

            public Builder logger(String logger) {
                this.logger = logger;
                return this;
            }

            public Builder data(String data) {
                this.data = data;
                return this;
            }

            public LoggingMessageNotification build() {
                return new LoggingMessageNotification(level, logger, data);
            }
        }
    }

    public enum LoggingLevel {
        @JsonProperty("debug") DEBUG(0),
        @JsonProperty("info") INFO(1),
        @JsonProperty("notice") NOTICE(2),
        @JsonProperty("warning") WARNING(3),
        @JsonProperty("error") ERROR(4),
        @JsonProperty("critical") CRITICAL(5),
        @JsonProperty("alert") ALERT(6),
        @JsonProperty("emergency") EMERGENCY(7);

        private final int level;

        LoggingLevel(int level) {
            this.level = level;
        }

        public int level() {
            return level;
        }

        public int getLevel() {
            return level;
        }
    }


    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class SetLevelRequest {
        private final LoggingLevel level;

        public SetLevelRequest(@JsonProperty("level") LoggingLevel level) {

            this.level = level;
        }

        public LoggingLevel level() {
            return level;
        }

        public LoggingLevel getLevel() {
            return level;
        }
    }

    // ---------------------------
    // Autocomplete
    // ---------------------------
    public interface CompleteReference {

        String type();

        String identifier();

    }


    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class PromptReference implements McpSchema.CompleteReference {

        private final String type;
        private final String name;

        public PromptReference(String name) {
            this("ref/prompt", name);
        }

        public PromptReference(String type, String name) {

            this.type = type;
            this.name = name;
        }

        @Override
        public String identifier() {
            return name();
        }

        public String type() {
            return type;
        }

        public String name() {
            return name;
        }

        public String getName() {
            return name;
        }

        public String getType() {
            return type;
        }
    }

    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class ResourceReference implements McpSchema.CompleteReference {

        private final String type;
        private final String uri;

        public ResourceReference(
                @JsonProperty("type") String type,
                @JsonProperty("uri") String uri) {

            this.type = type;
            this.uri = uri;
        }

        public ResourceReference(String uri) {
            this("ref/resource", uri);
        }

        @Override
        public String identifier() {
            return uri();
        }

        public String uri() {
            return uri;
        }

        @Override
        public String type() {
            return type;
        }

        public String getType() {
            return type;
        }

        public String getUri() {
            return uri;
        }
    }


    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class CompleteRequest implements Request {

        private final CompleteReference ref;
        private final CompleteArgument argument;

        public CompleteRequest(
                @JsonProperty("ref") McpSchema.CompleteReference ref,
                @JsonProperty("argument") CompleteArgument argument) {

            this.ref = ref;
            this.argument = argument;
        }

        public CompleteReference ref() {
            return ref;
        }

        public CompleteArgument argument() {
            return argument;
        }

        public static class CompleteArgument {
            private final String name;
            private final String value;

            public CompleteArgument(
                    @JsonProperty("name") String name,
                    @JsonProperty("value") String value) {

                this.name = name;
                this.value = value;
            }

            public String name() {
                return name;
            }

            public String value() {
                return value;
            }
        }
    }

    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class CompleteResult  {

        private final CompleteCompletion completion;

        public CompleteResult(@JsonProperty("completion") CompleteCompletion completion){

            this.completion = completion;
        }

        public CompleteCompletion completion() {
            return completion;
        }

        public CompleteCompletion getCompletion() {
            return completion;
        }

        public static class CompleteCompletion{
            private final List<String> values;
            private final Integer total;
            private final Boolean hasMore;

            public CompleteCompletion(
                    @JsonProperty("values") List<String> values,
                    @JsonProperty("total") Integer total,
                    @JsonProperty("hasMore") Boolean hasMore) {
                this.values = values;
                this.total = total;
                this.hasMore = hasMore;
            }

            public Boolean hasMore() {
                return hasMore;
            }

            public int total() {
                return total;
            }

            public List<String> values() {
                return values;
            }
        }
    }

    // 这里假设 Content 和 TextContent 类已经定义，如果没有定义，需要补充定义
    public interface Content {
    }

    public static class TextContent implements Content {
        private final String text;

        public TextContent(String text) {
            this.text = text;
        }

        public String text() {
            return text;
        }

        public String getText() {
            return text;
        }


        public String type(){
            return "text";
        }

        public String getType(){
            return type();
        }
    }


    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class ImageContent implements Content {
        private final List<Role> audience;
        private final Double priority;
        private final String data;
        private final String mimeType;

        public ImageContent(
                @JsonProperty("audience") List<Role> audience,
                @JsonProperty("priority") Double priority,
                @JsonProperty("data") String data,
                @JsonProperty("mimeType") String mimeType) {

            this.audience = audience;
            this.priority = priority;
            this.data = data;
            this.mimeType = mimeType;
        }

        public String type(){
            return "image";
        }

        public String getType(){
            return type();
        }

        public List<Role> audience() {
            return audience;
        }

        public Double priority() {
            return priority;
        }

        public String data() {
            return data;
        }

        public String mimeType() {
            return mimeType;
        }

        public String getMimeType() {
            return mimeType;
        }

        public String getData() {
            return data;
        }

        public List<Role> getAudience() {
            return audience;
        }

        public Double getPriority() {
            return priority;
        }
    }

    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class EmbeddedResource implements Content {
        private final List<Role> audience;
        private final Double priority;
        private final ResourceContents resource;

        public EmbeddedResource(
                @JsonProperty("audience") List<Role> audience,
                @JsonProperty("priority") Double priority,
                @JsonProperty("resource") ResourceContents resource) {

            this.audience = audience;
            this.priority = priority;
            this.resource = resource;
        }
        public String type(){
            return "resource";
        }

        public String getType(){
            return type();
        }

        public List<Role> audience() {
            return audience;
        }

        public Double priority() {
            return priority;
        }

        public ResourceContents resource() {
            return resource;
        }

        public List<Role> getAudience() {
            return audience;
        }

        public Double getPriority() {
            return priority;
        }

        public ResourceContents getResource() {
            return resource;
        }
    }

    // ---------------------------
    // Roots
    // ---------------------------
    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class Root {
        private final String uri;
        private final String name;

        public Root(
                @JsonProperty("uri") String uri,
                @JsonProperty("name") String name) {

            this.uri = uri;
            this.name = name;
        }

        public String uri() {
            return uri;
        }

        public String name() {
            return name;
        }

        public String getName() {
            return name;
        }

        public String getUri() {
            return uri;
        }
    }

    @JsonInclude(JsonInclude.Include.NON_ABSENT)
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class ListRootsResult {
        private final List<Root> roots;

        public ListRootsResult(
                @JsonProperty("roots") List<Root> roots) {

            this.roots = roots;
        }

        public List<Root> roots() {
            return roots;
        }

        public List<Root> getRoots() {
            return roots;
        }
    }

}